package com.bestcem.xm.label.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.label.constant.Constants;
import com.bestcem.xm.label.dao.LabelDao;
import com.bestcem.xm.label.dao.LabelGroupDao;
import com.bestcem.xm.label.dao.LabelValueDao;
import com.bestcem.xm.label.entity.pojo.LabelDO;
import com.bestcem.xm.label.entity.pojo.LabelGroupDO;
import com.bestcem.xm.label.entity.pojo.LabelValueDO;
import com.bestcem.xm.label.grpc.service.param.label.ListLabelsParam;
import com.bestcem.xm.label.grpc.service.param.labelgroup.CreateLabelGroupParam;
import com.bestcem.xm.label.grpc.service.param.labelgroup.UpdateLabelGroupNameParam;
import com.bestcem.xm.label.service.LabelGroupService;
import com.bestcem.xm.label.service.dto.LabelGroupDTO;
import com.bestcem.xm.label.service.dto.label.LabelDTO;
import com.bestcem.xm.label.service.dto.label.LabelInfoDTO;
import com.bestcem.xm.label.service.dto.label.LabelValueDTO;
import com.bestcem.xm.member.service.GroupService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author dc.wang <dc.wang@idiaoyan.com>
 * @description 提供标签组相关服务
 * @date 2021/5/18 @Version V1.0
 */
@Slf4j
@Service
public class LabelGroupServiceImpl implements LabelGroupService {

    private final LabelGroupDao labelGroupDao;

    private final LabelDao labelDao;

    private final LabelValueDao labelValueDao;

    @Resource
    private GroupService groupService;

    @Autowired
    public LabelGroupServiceImpl(LabelGroupDao labelGroupDao, LabelDao labelDao, LabelValueDao labelValueDao) {
        this.labelGroupDao = labelGroupDao;
        this.labelDao = labelDao;
        this.labelValueDao = labelValueDao;
    }

    /**
     * 查询企业标签组
     *
     * @param orgId 企业ID
     * @return List<LabelGroupDTO>
     */
    @Override
    public ServiceResult<List<LabelGroupDTO>> listLabelGroup(String orgId) {
        if (!Pattern.matches(RegTypes.OBJECT_ID, orgId)) {
            return ServiceResult.fail(String.format("企业ID：%s 异常！", orgId));
        }

        List<LabelGroupDO> labelGroups = labelGroupDao.list(orgId);

        List<LabelGroupDTO> resData = new ArrayList<>(labelGroups.size());
        for (LabelGroupDO entity : labelGroups) {
            LabelGroupDTO labelGroupDTO = LabelGroupDTO.convert(entity);
            resData.add(labelGroupDTO);
        }

        return ServiceResult.success(resData);
    }

    @Override
    public ServiceResult<LabelGroupDTO> createLabelGroup(CreateLabelGroupParam param) {
        // 校验企业中同名标签组
        boolean existMultiName = labelGroupDao.containsDuplicate(param.getOrgId(), param.getName());
        if (existMultiName) {
            return ServiceResult.fail("标签组名重复！");
        }

        LabelGroupDO labelGroup = new LabelGroupDO();
        labelGroup.setName(param.getName());
        labelGroup.setOrgId(param.getOrgId());
        labelGroup.setMemberType(param.getAttribute());
        labelGroup.setSeq(param.getSerial());
        labelGroup.setCreateTime(DateUtil.getCommonDate());
        labelGroup.setUpdateTime(labelGroup.getCreateTime());

        // 校验企业中标签组的数量不超过20
        Integer labelGroupSize = labelGroupDao.count(labelGroup);
        if (labelGroupSize >= Constants.TAG_GROUP_MAX_LEN) {
            return ServiceResult.fail("标签组数量不能超过20个！");
        }

        // 非原子性，必要时调整
        LabelGroupDO createdTagGroup = labelGroupDao.insert(labelGroup);
        LabelGroupDTO labelGroupDTO = LabelGroupDTO.convert(createdTagGroup);

        return ServiceResult.success(labelGroupDTO);
    }

    @Override
    public ServiceResult<String> updateLabelGroup(UpdateLabelGroupNameParam updateLabelGroupNameParam) {
        // 校验企业中同名标签组
        boolean existMultiName = labelGroupDao.containsDuplicate(updateLabelGroupNameParam.getOrgId(), updateLabelGroupNameParam.getName());
        if (existMultiName) {
            return ServiceResult.fail("标签组名重复！");
        }

        LabelGroupDO labelGroup = new LabelGroupDO();
        labelGroup.setId(updateLabelGroupNameParam.getLabelGroupId());
        labelGroup.setOrgId(updateLabelGroupNameParam.getOrgId());
        labelGroup.setName(updateLabelGroupNameParam.getName());
        labelGroup.setUpdateTime(DateUtil.getCommonDate());
        labelGroupDao.updateNameById(labelGroup);
        // 更新标签值中的标签组名
        labelValueDao.updateLabelGroupInfo(labelGroup);

        return ServiceResult.success(updateLabelGroupNameParam.getLabelGroupId());
    }


    @Override
    public ServiceResult<LabelGroupDTO> deleteLabelGroup(String labelGroupId) {
        // 删除标签值
        Boolean deleteResult = labelValueDao.deleteByLabelGroupId(labelGroupId);
        if (!deleteResult) {
            log.error("删除标签组ID：{} 的标签值失败！", labelGroupId);
            return ServiceResult.fail("删除标签组中的标签失败！");
        }

        // 删除标签
        List<LabelDO> labels = labelDao.deleteAndListByLabelGroupId(null, labelGroupId);
        List<LabelDTO> labelDTOS = labels.stream().map(this::convertToLabelDTO).collect(Collectors.toList());

        // 删除标签组
        LabelGroupDO labelGroup = labelGroupDao.delete(labelGroupId);

        //添加删除的标签DTO
        LabelGroupDTO labelGroupDTO = LabelGroupDTO.convert(labelGroup);
        labelGroupDTO.setLabelDTOS(labelDTOS);

        // 异步更新联系人分组信息
        if(!CollectionUtil.isEmpty(labels)){
            groupService.sendGroupMessages(labelGroup.getOrgId());
        }

        return ServiceResult.success(labelGroupDTO);
    }

    /**
     * Label转化LabelDTO
     *
     * @param label 标签
     * @author dc.wang <dc.wang@idiaoyan.com>
     * @date 2021/6/25
     */
    private LabelDTO convertToLabelDTO(LabelDO label) {
        LabelDTO labelDTO = new LabelDTO();
        if (label != null) {
            labelDTO.setId(label.getLabelId());
        }

        return labelDTO;
    }

    @Override
    public List<LabelInfoDTO> listLabels(ListLabelsParam param) {
        List<LabelInfoDTO> labelInfoDTOS = labelGroupDao.listByParam(param);
        // 包含了标签值
        if (param.getIncludeValue()) {
            if (CollectionUtil.isNotEmpty(labelInfoDTOS)) {
                // 获取该组织下所有的标签值
                List<LabelValueDO> labelValues = labelValueDao.listByOrgIdAndMemberTypeSortBySerial(param.getOrgId(), param.getAttribute());
                // 组装数据
                if (CollectionUtil.isNotEmpty(labelValues)) {
                    // 根据标签id分组 和原有顺序一致
                    LinkedHashMap<String, List<LabelValueDO>> labelValueMap =
                            labelValues.stream().collect(Collectors.groupingBy(LabelValueDO::getLabelId, LinkedHashMap::new, Collectors.toList()));
                    labelInfoDTOS.forEach(labelGroup -> {
                        List<LabelDTO> labels = labelGroup.getLabels();
                        if (CollectionUtil.isNotEmpty(labels)) {
                            // 若存在标签列表，则循环添加标签值
                            labels.forEach(label -> {
                                String id = label.getId();
                                if (labelValueMap.containsKey(id)) {
                                    // 该标签有标签值
                                    List<LabelValueDO> labelValues1 = labelValueMap.get(id);
                                    List<LabelValueDTO> labelValueDTOS = new ArrayList<>(labelValues1.size());
                                    if (CollectionUtil.isNotEmpty(labelValues1)) {
                                        // 转DTO
                                        labelValues1.forEach(labelValue -> {
                                            LabelValueDTO convert = LabelValueDTO.convert(labelValue);
                                            labelValueDTOS.add(convert);
                                        });
                                    }
                                    label.setValues(labelValueDTOS);
                                }
                            });
                        }
                    });
                }
            }
        }
        return labelInfoDTOS;
    }

    @Override
    public LabelGroupDO findById(String labelGroupId) {
        return labelGroupDao.getById(labelGroupId);
    }
}
